package com.yst.sqlbuilder;

import com.yst.lambda.LambdaFuncUtils;
import com.yst.lambda.TableFieldFunc;
import com.yst.util.ClassUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class EntityMapConfig implements IEntitiesConfig {

    private Class<? extends Annotation> tableAnnotation;
    private Class<? extends Annotation> fieldAnnotation;

    private final Map<String,String> tableAlias= Collections.synchronizedMap(new HashMap<>());
    private final Map<String,Map<String,String>> fieldAlias=Collections.synchronizedMap(new HashMap<>());

    public EntityMapConfig setTableAnnotation(Class<? extends Annotation> tableAnnotationClass){
        this.tableAnnotation=tableAnnotationClass;
        return this;
    }
    public EntityMapConfig setFieldAnnotation(Class<? extends Annotation> fieldAnnotationClazz){
        this.fieldAnnotation=fieldAnnotationClazz;
        return this;
    }

    private Method tableNameField;
    public EntityMapConfig setTableNameField(String tableNameField){
        try {
            this.tableNameField = this.tableAnnotation.getMethod(tableNameField);
        }
        catch (Exception ignored){

        }
        return this;
    }

    @Override
    public String getTableName(Class<?> clazz){
        try {
            if (tableAlias.containsKey(clazz.getSimpleName())){
                return tableAlias.get(clazz.getSimpleName());
            }
            if (Objects.nonNull(tableAnnotation)) {
                Annotation annotation = clazz.getAnnotation(tableAnnotation);
                if (Objects.nonNull(annotation)) {
                    String tableName= (String) tableNameField.invoke(annotation);
                    tableAlias.put(clazz.getSimpleName(),tableName);
                    return tableName;
                }
            }
        }
        catch (Exception ignore){

        }
        tableAlias.put(clazz.getSimpleName(),clazz.getSimpleName());
        return clazz.getSimpleName();
    }

    private Method fieldNameField;
    public EntityMapConfig setFieldNameField(String fieldNameField){
        try {
            this.fieldNameField = this.fieldAnnotation.getMethod(fieldNameField);
        }
        catch (Exception ignored){

        }
        return this;
    }
    public String getFieldName(Class<?> clazz,String fieldName){
        if (fieldAlias.containsKey(clazz.getSimpleName())){
            Map<String,String> fieldMap=fieldAlias.get(clazz.getSimpleName());
            if (Objects.nonNull(fieldMap)){
                return fieldMap.getOrDefault(fieldName,fieldName);
            }
        }
        Map<String, Field> fieldMap= ClassUtils.getClassFields(clazz);
        if (Objects.nonNull(fieldMap)) {
            Map<String,String> fieldAliasMap=new LinkedHashMap<>();
            fieldAlias.put(clazz.getSimpleName(),fieldAliasMap);
            for(String tmpFieldName:fieldMap.keySet()) {
                if (fieldMap.containsKey(fieldName)) {
                    Field field = fieldMap.get(tmpFieldName);
                    Annotation annotation = field.getAnnotation(fieldAnnotation);
                    if (Objects.nonNull(annotation)) {
                        try {
                            String fieldNameAlias= (String) fieldNameField.invoke(annotation);
                            fieldAliasMap.put(fieldName,fieldNameAlias);
                        } catch (Exception ignored) {
                        }
                    }
                }
            }
            return fieldAliasMap.getOrDefault(fieldName,fieldName);
        }
        return fieldName;
    }


    private static final EntityMapConfig defaultConfig;
    static {
        defaultConfig=new EntityMapConfig()
                .setTableAnnotation(DataTable.class)
                .setTableNameField("value")
                .setFieldAnnotation(DataColumn.class)
                .setFieldNameField("value");
    }
    public static EntityMapConfig getDefault(){
        return defaultConfig;
    }

    @Override
    public String getFieldName(TableFieldFunc<?,?> field) {
        String fullClassName=LambdaFuncUtils.getOwnerClassName(field);
        String fieldName=LambdaFuncUtils.getFieldName(field);
        try {
            Class<?> clazz = Class.forName(fullClassName);
            return getFieldName(clazz,fieldName);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return fieldName;
    }

    @Override
    public String getFieldName(String className, String fieldName) {
        return null;
    }
}
